#include "Pinyin.h"

#include <core/Utility.h>
#include <core/strings/pinyin.h>
#include <core/strings/pinyin_search.h>
#include <core/strings/string_convert.h>
#include <core/sync/lock.h>
#include <stdint.h>
#include <string.h>

#include <list>

typedef qb::base::Spell Spell;
namespace qb {
namespace {
/*
计算一个UTF8字符的长度
返回结果
1   表示成功，bsize有效
0   表示不完整的UTF8字符
-1  表示失败，无效的UTF8字符
*/
int CalcUTF8Char(const char* buffer, int buflen, int& bsize) {
  bsize = 0;
  if (buffer == NULL || buflen <= 0) return -1;

  unsigned char uv = (unsigned char)buffer[0];
  if (uv <= 127) {
    bsize = 1;
    return 1;
  }

  unsigned char mask = 0x80;
  int msize = 0;
  for (msize = 0; msize < 8; ++msize) {
    if ((uv & mask) == 0) break;

    mask = mask >> 1;
  }

  int idx;
  for (idx = 1; (idx < msize) && (idx < buflen); ++idx) {
    uv = (unsigned char)buffer[idx];
    if ((uv & 0xc0) != 0x80) return -1;
  }

  if (idx != msize) return 0;

  bsize = msize;
  return 1;
}
char utf8s[256] = {0};
bool ParseUTF8Stream(const std::string& utf8, std::list<std::string>& chars) {
  chars.clear();
  const char* str = utf8.c_str();
  int slen = (int)utf8.length(), bsize = 0;
  while (CalcUTF8Char(str, slen, bsize) == 1) {
    memset(utf8s, 0, 256);
    memcpy(utf8s, str, bsize);
    utf8s[bsize] = '\0';

    chars.push_back(utf8s);
    str += bsize;
    slen -= bsize;
  }

  return (chars.empty() == false);
}

// 仅仅使得下面代码能够编译,真实情况不会使用
static const unsigned char utf8_pinyin_cont[] = {
    (unsigned char)'\x09', (unsigned char)'\xe3', (unsigned char)'\x80',
    (unsigned char)'\x87', (unsigned char)'\0',   (unsigned char)'\x6c',
    (unsigned char)'\x69', (unsigned char)'\x6e', (unsigned char)'\x67',
    (unsigned char)'\0'};
static const int PINYIN_CONT_MAX_SIZE = 2;

static void string_ToLower(std::string& SrcString) {
  for (auto i = SrcString.begin(); i != SrcString.end(); i++)
    if (*i >= 'A' && *i <= 'Z') *i = (*i) + ('a' - 'A');
}

static void string_ToUpper(std::string& SrcString) {
  for (auto i = SrcString.begin(); i != SrcString.end(); i++)
    if (*i >= 'a' && *i <= 'z') *i = (*i) - ('a' - 'A');
}
}  // namespace
/////////////////////////////////////////////////////////////////////////////////////
class PinyinManagerImpl : public IPinyin {
  enum { BUFLENGTH = 1024 };
  qb::base::CConvertFast m_converter;
  wchar_t* m_quan_buffer;
  wchar_t* m_jian_buffer;
  qb::base::CSLock m_lock;

 public:
  PinyinManagerImpl() {
    m_quan_buffer = new wchar_t[BUFLENGTH];
    m_jian_buffer = new wchar_t[BUFLENGTH];
    memset(m_quan_buffer, 0, BUFLENGTH * sizeof(wchar_t));
    memset(m_jian_buffer, 0, BUFLENGTH * sizeof(wchar_t));
  }
  ~PinyinManagerImpl() {
    if (m_quan_buffer) delete m_quan_buffer;
    if (m_jian_buffer) delete m_jian_buffer;
  }
  virtual void GetPinyinBuffer(const char* buffer, wchar_t* jianbuf,
                               int& jianlen, wchar_t* quanbuf, int& quanlen) {
    SCOPED_LOCK(m_lock);
    const wchar_t* name = m_converter.ToWide(buffer, strlen(buffer));
    Spell::Parse(name, m_converter.GetWstrSize(), quanbuf, quanlen, jianbuf,
                 jianlen);
  }
  virtual void GetPinyin(const char* buffer, std::string& sJianpin,
                         std::string& sQuanpin, IPinyin::kFlag flag) {
    SCOPED_LOCK(m_lock);
    int flen = BUFLENGTH - 1, slen = BUFLENGTH - 1;
    m_quan_buffer[0] = 0;
    m_jian_buffer[0] = 0;
    if (flag == IPinyin::kFlagJian) flen = 0;
    if (flag == IPinyin::kFlagFull) slen = 0;
    const wchar_t* name = m_converter.ToWide(buffer, strlen(buffer));
    Spell::Parse(name, m_converter.GetWstrSize(), m_quan_buffer, flen,
                 m_jian_buffer, slen);
    if (flag == IPinyin::kFlagJian || flag == IPinyin::kFlagBoth) {
      const char* pGBK = m_converter.ToGbk(m_jian_buffer, slen);
      sJianpin = (pGBK ? pGBK : "");
    }

    if (flag == IPinyin::kFlagFull || flag == IPinyin::kFlagBoth) {
      const char* pGBK = m_converter.ToGbk(m_quan_buffer, flen);
      sQuanpin = (pGBK ? pGBK : "");
    }
  }
  virtual const std::string GetPinyin(const char* buffer) {
    SCOPED_LOCK(m_lock);
    std::wstring name = m_converter.ToWide(buffer, strlen(buffer));
    wchar_t jian[1024] = {0};
    int flen = 0, slen = 1024;
    Spell::Parse(name.c_str(), name.size(), 0, flen, jian, slen);
    const char* pGBK = m_converter.ToGbk(jian, slen);
    return (pGBK ? pGBK : "");
  }
  virtual void Dump(int select) { SCOPED_LOCK(m_lock); }
};

/////////////////////////////////////////////////////////////////////////////////////
/*
使用vector而不是set，主要是为了保持拼音的顺序
*/
class Pinyins : public std::vector<std::string> {
 public:
  static const Pinyins EMPTY;
};

const Pinyins Pinyins::EMPTY;
/////////////////////////////////////////////////////////////////////////////////////
PinyinManager::PinyinManager() : m_impl(0) {
  // 如果不需要使用新的实现,将如下代码行注释掉即可
  m_impl = new PinyinManagerImpl();

  // BLOGINFO("使用%s字典实现,花费%dms", newimpl ? "新" : "旧",
  // time.elapsed().minisec());
}
PinyinManager::~PinyinManager() {
  if (m_impl) delete m_impl;
}

void PinyinManager::GetPinyinBuffer(const char* buffer, wchar_t* jianbuf,
                                    int& jianlen, wchar_t* quanbuf,
                                    int& quanlen) {
  m_impl->GetPinyinBuffer(buffer, jianbuf, jianlen, quanbuf, quanlen);
}
void PinyinManager::GetPinyin(const char* buffer, std::string& sJianpin,
                              std::string& sQuanpin, IPinyin::kFlag flag) {
  m_impl->GetPinyin(buffer, sJianpin, sQuanpin, flag);
}

const std::string PinyinManager::GetPinyin(const char* buffer) {
  return m_impl->GetPinyin(buffer);
}
void PinyinManager::Dump(int select) {
  if (m_impl) m_impl->Dump(select);
}
}  // namespace qb

qb::PinyinManager& qb::PinyinManager::instance() {
  static qb::PinyinManager s_pm;
  return s_pm;
}
